﻿/**	matrix.h
 *	----	Create Time Stamp	--2006-06-19 23:33:35--
 *-----------------------------------------------------------------------------
 *	Mean	:矩阵
 *	Author	:Nick Shallery	(nicknide@gmail.com)
 *	Version	:1.0.7.10	(2007-12-22 21:39:24)
 *-----------------------------------------------------------------------------
**/	/*YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.*/


#if			!defined(__LOLIX__SOLA__MATRIX__K_IN_G__)
#define		__LOLIX__SOLA__MATRIX__K_IN_G__
#ifdef		__cplusplus


#if			!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)
	#include	"../lolix_cfg.h"
#endif	//	!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)


#if			LOLIX_CFG__PER_CHECK_FILE_CHUNK_SPACE
	#if			!defined(__LOLIX__SOLA__VECTOR__NICK__K_IN_G__)
		#include	"./vector.h"
	#endif	//	!defined(__LOLIX__SOLA__VECTOR__NICK__K_IN_G__)
#else	//	LOLIX_CFG__PER_CHECK_FILE_CHUNK_SPACE
	#include	"./vector.h"
#endif	//	LOLIX_CFG__PER_CHECK_FILE_CHUNK_SPACE


//#include	"../code/main.h"
/////////////////////////////////////////////////////////////////////
//			vec[0][0]	vec[1][0]	vec[2][0]	....	vec[n-1][0]
//			vec[0][1]	vec[1][1]	vec[2][1]	....	vec[n-1][1]
//			vec[0][2]	vec[1][2]	vec[2][2]	....	vec[n-1][2]
//.....		....		....		....		....	....
//			vec[0][n-1]	vec[1][n-1]	vec[2][n-1]	....	vec[n-1][n-1]



template<unsigned int dim, typename v_type>
class lolix::sola::matrix
	: public lolix::sola::_help::matrix_base<dim, v_type>
{
	typedef matrix_base<dim, v_type>	base_type;
	typedef matrix<dim, v_type>	this_type;
	typedef this_type&			this_ref;
	typedef const this_type&	this_const_ref;
public:
	this_type(void){}
	void identity(void)
	{
		for(unsigned int i = 0; i < dim; ++i)
		{
			unsigned int j;
			for(j = 0; j < i; ++j)	vec[j][i] = v_type(0);
									vec[j][i] = v_type(1);
			for(++j; j < dim; ++j)	vec[j][i] = v_type(0);
		}
	}

	void transpose(void)
	{
		v_type tmp;
		for ( unsigned int i = 0; i < dim-1; ++i )
			for ( unsigned int j = i+1; j < dim; ++j )
			{
				tmp = vec[i][j]; vec[i][j] = vec[j][i]; vec[j][i] = tmp;
			}
	}

	this_ref operator *= (this_const_ref o)
	{
		transpose();
		this_type tmp(*this);
		for ( unsigned int i = 0; i < dim; ++i )
			for ( unsigned int j = 0; j < dim; ++j )
			{
				vec[i][j] = tmp.vec[i].dot(o.vec[j]);
			}

		return *this;
	}

	this_type operator*(this_const_ref o)const
	{
		this_type tmp(*this);
		return tmp*= o;
	}

	vector<dim, v_type>& operator[](unsigned int pos)
	{ return vec[pos]; }
	const vector<dim, v_type>& operator[](unsigned int pos)const
	{ return vec[pos]; }

	vector<dim, v_type> vec[dim];
};


template<typename v_type>
class lolix::sola::matrix<3, v_type>
	: public lolix::sola::_help::matrix_base<3, v_type>
{
	typedef matrix_base<3, v_type>	base_type;
	typedef matrix<3, v_type>	this_type;
	typedef this_type&			this_ref;
	typedef const this_type&	this_const_ref;
public:
	void	identity(void)
	{
		vec[0][0]=v_type(1);vec[0][1]=v_type(0);vec[0][2]=v_type(0);
		vec[1][0]=v_type(0);vec[1][1]=v_type(1);vec[1][2]=v_type(0);
		vec[2][0]=v_type(0);vec[2][1]=v_type(0);vec[2][2]=v_type(1);
	}

	void	transpose(void)
	{
		v_type tmp;
		tmp = vec[0][1]; vec[0][1] = vec[1][0]; vec[1][0] = tmp;
		tmp = vec[0][2]; vec[0][2] = vec[2][0]; vec[2][0] = tmp;
		tmp = vec[1][2]; vec[1][2] = vec[2][1]; vec[2][1] = tmp;
	}

	this_ref operator*=(this_const_ref o)
	{
		transpose();
		this_type tmp(*this);
		vec[0][0] = tmp[0].dot(o.vec[0]);
		vec[0][1] = tmp[1].dot(o.vec[0]);
		vec[0][2] = tmp[2].dot(o.vec[0]);

		vec[1][0] = tmp[0].dot(o.vec[1]);
		vec[1][1] = tmp[1].dot(o.vec[1]);
		vec[1][2] = tmp[2].dot(o.vec[1]);

		vec[2][0] = tmp[0].dot(o.vec[2]);
		vec[2][1] = tmp[1].dot(o.vec[2]);
		vec[2][2] = tmp[2].dot(o.vec[2]);

		return *this;
	}


	const this_type operator *(this_const_ref o)const
	{
		this_type tmp(*this);
		return tmp*=o;
	}


	const vector<3, v_type> operator * (const vector<3, v_type>& v3)const
	{
		vector<3, v_type> vtmp;
		vector<3, v_type> vret;
		vtmp(this->vec[0][0], this->vec[1][0], this->vec[2][0]);
		vret[0] = vtmp.dot(v3);
		vtmp(this->vec[0][1], this->vec[1][1], this->vec[2][1]);
		vret[1] = vtmp.dot(v3);
		vtmp(this->vec[0][2], this->vec[1][2], this->vec[2][2]);
		vret[2] = vtmp.dot(v3);
		return vret;
	}

	vector<3, v_type>& operator[](unsigned int pos)
	{ return vec[pos]; }
	const vector<3, v_type>& operator[](unsigned int pos)const
	{ return vec[pos]; }

	vector<3, v_type>	vec[3];
};


template<typename v_type>
class lolix::sola::matrix<4, v_type>
	: public lolix::sola::_help::matrix_base<4, v_type>
{
	typedef matrix<4, v_type>		this_type;
	typedef matrix_base<4, v_type>	base_type;

	typedef	this_type&				this_ref;
	typedef const this_type&		this_const_ref;
public:
	matrix<4, v_type>(void){}
	matrix<4, v_type>(const matrix<4, v_type>& o)
	{
		*this = o;
	}

	matrix<4, v_type>& operator = (const matrix<4, v_type>& o)
	{
#define	_VCP_(x, y)	vec[x][y] = o[x][y]
		_VCP_(0, 0);_VCP_(1, 0);_VCP_(2, 0);_VCP_(3, 0);
		_VCP_(0, 1);_VCP_(1, 1);_VCP_(2, 1);_VCP_(3, 1);
		_VCP_(0, 2);_VCP_(1, 2);_VCP_(2, 2);_VCP_(3, 2);
		_VCP_(0, 3);_VCP_(1, 3);_VCP_(2, 3);_VCP_(3, 3);
#undef	_VCP_
		return *this;
	}

	void identity(void)
	{
		vec[0][0]=v_type(1);vec[1][0]=v_type(0);vec[2][0]=v_type(0);vec[3][0]=v_type(0);
		vec[0][1]=v_type(0);vec[1][1]=v_type(1);vec[2][1]=v_type(0);vec[3][1]=v_type(0);
		vec[0][2]=v_type(0);vec[1][2]=v_type(0);vec[2][2]=v_type(1);vec[3][2]=v_type(0);
		vec[0][3]=v_type(0);vec[1][3]=v_type(0);vec[2][3]=v_type(0);vec[3][3]=v_type(1);
	}

	void transpose(void)
	{
		v_type tmp;
		tmp = vec[0][1]; vec[0][1] = vec[1][0]; vec[1][0] = tmp;
		tmp = vec[0][2]; vec[0][2] = vec[2][0]; vec[2][0] = tmp;
		tmp = vec[0][3]; vec[0][3] = vec[3][0]; vec[3][0] = tmp;

		tmp = vec[1][2]; vec[1][2] = vec[2][1]; vec[2][1] = tmp;
		tmp = vec[1][3]; vec[1][3] = vec[3][1]; vec[3][1] = tmp;

		tmp = vec[2][3]; vec[2][3] = vec[3][2]; vec[3][2] = tmp;
	}

	this_ref operator*=(this_const_ref o)
	{
		transpose();
		this_type tmp(*this);
		vec[0][0] = tmp[0].dot(o.vec[0]);
		vec[0][1] = tmp[1].dot(o.vec[0]);
		vec[0][2] = tmp[2].dot(o.vec[0]);
		vec[0][3] = tmp[3].dot(o.vec[0]);

		vec[1][0] = tmp[0].dot(o.vec[1]);
		vec[1][1] = tmp[1].dot(o.vec[1]);
		vec[1][2] = tmp[2].dot(o.vec[1]);
		vec[1][3] = tmp[3].dot(o.vec[1]);

		vec[2][0] = tmp[0].dot(o.vec[2]);
		vec[2][1] = tmp[1].dot(o.vec[2]);
		vec[2][2] = tmp[2].dot(o.vec[2]);
		vec[2][3] = tmp[3].dot(o.vec[2]);

		vec[3][0] = tmp[0].dot(o.vec[3]);
		vec[3][1] = tmp[1].dot(o.vec[3]);
		vec[3][2] = tmp[2].dot(o.vec[3]);
		vec[3][3] = tmp[3].dot(o.vec[3]);

		return *this;
	}

	//	行列式的值: 好像有问题
	//v_type	det(void)const
	//{
	//	v_type val = 
	//		   vec[0][0]*vec[1][1]*vec[2][2]*vec[3][3];
	//	val += vec[1][0]*vec[2][1]*vec[3][2]*vec[0][3];
	//	val += vec[2][0]*vec[3][1]*vec[0][2]*vec[1][3];
	//	val += vec[3][0]*vec[0][1]*vec[1][2]*vec[2][3];
	//	val -= vec[0][0]*vec[3][1]*vec[2][2]*vec[1][3];
	//	val -= vec[1][0]*vec[0][1]*vec[3][2]*vec[2][3];
	//	val -= vec[2][0]*vec[1][1]*vec[0][2]*vec[3][3];
	//	val -= vec[3][0]*vec[2][1]*vec[1][2]*vec[0][3];
	//	return val;
	//}

	this_type operator *(this_const_ref o)const
	{
		this_type tmp(*this);
		return tmp*=o;
	}

	vector<4, v_type> operator * (vector<4, v_type>& v4)const
	{
		vector<4, v_type> vtmp;
		vector<4, v_type> vret;
		vtmp(this->vec[0][0], this->vec[1][0], this->vec[2][0], this->vec[3][0]);
		vret[0] = vtmp.dot(v4);
		vtmp(this->vec[0][1], this->vec[1][1], this->vec[2][1], this->vec[3][1]);
		vret[1] = vtmp.dot(v4);
		vtmp(this->vec[0][2], this->vec[1][2], this->vec[2][2], this->vec[3][2]);
		vret[2] = vtmp.dot(v4);
		vtmp(this->vec[0][3], this->vec[1][3], this->vec[2][3], this->vec[3][3]);
		vret[3] = vtmp.dot(v4);
		return vret;
	}

	vector<4, v_type>& operator[](unsigned int pos)
	{ return vec[pos]; }
	const vector<4, v_type>& operator[](unsigned int pos)const
	{ return vec[pos]; }

	this_ref	operator /= (v_type v)
	{
		for ( size_type i = 0; i != 4; ++i )
		{
			vec[i][0] /= v;
			vec[i][1] /= v;
			vec[i][2] /= v;
			vec[i][3] /= v;
		}

		return *this;
	}

	vector<4, v_type>	vec[4];
};


namespace	lolix{
	namespace sola{
		typedef	matrix<2, float>	mat2;
		typedef	matrix<3, float>	mat3;
		typedef	matrix<4, float>	mat4;

		typedef	matrix<2, double>	dmat2;
		typedef	matrix<3, double>	dmat3;
		typedef	matrix<4, double>	dmat4;
	}
}

#else	//	__cplusplus
#	error	Must Have C++ Complier Support
#endif	//	__cplusplus

#endif	//	!defined(__LOLIX__SOLA__MATRIX__K_IN_G__)
